package client;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Semaphore;

import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.Timer;

import utils.GameImages;
import utils.Piece;
import utils.Settings;
import utils.Utils;

import components.RPSRoundRect;

import enums.Direction;
import enums.Revealed;
import enums.Weapon;

/**
 * The animation of a fight between two pieces.
 */
public class WarShowFightAnimation extends JComponent  {

	private static final long serialVersionUID = 1L;
	
	private static final int CORNER = 40;	
	private static final int BOARD_END_WIDTH = 570;
	private static final int BOARD_END_HEIGHT = 650;
	private static final int RECT_WIDTH = 400;
	private static final int RECT_HEIGHT = 300;
	private static final int IMAGE_SIZE = 40;
	private static final double SPACING_SIDE = 50;
	private static final double SPACING_UP = 20;
	private static final Color BACKGROUND_COLOUR = new Color (255, 255, 255, 180);
	private static final Color BACKGROUND_STROKE_COLOUR = new Color (100, 100, 100);
	
	private static final double ANIMATION_TIME = 3;
	private static final int MOVE_PIECE_ANIMATION_SPEED = 50;
	private static final double ANIMATION_MOVES = ((ANIMATION_TIME) / (MOVE_PIECE_ANIMATION_SPEED / 1000.0));

	private RPSRoundRect roundRect = new RPSRoundRect(new Dimension(BOARD_END_WIDTH, BOARD_END_HEIGHT) ,
													  RECT_WIDTH, RECT_HEIGHT, CORNER ,
													  BACKGROUND_COLOUR, BACKGROUND_STROKE_COLOUR);
	private Timer timer = null;
	private int counter = 1;
	private Piece me;
	private Piece enemy;
	private BufferedImage enemyWeaponImg = null;
	private BufferedImage myWeaponImg = null;

	private BufferedImage p1 = null;
	private BufferedImage p2 = null;
	private double closeMeScale = 0;
	private double closeEnemyScale = 0;
	private BufferedImage myWeaponImgOrg;
	private BufferedImage enemyWeaponImgOrg;
	private Semaphore sem;
	
	public WarShowFightAnimation (Piece myPiece , Piece enemyPiece) {
	
		super();
		
		setOpaque(false);
		setBounds((BOARD_END_WIDTH -RECT_WIDTH)/2 , (BOARD_END_HEIGHT -RECT_HEIGHT)/2, RECT_WIDTH, RECT_HEIGHT);
		
		me = myPiece;
		enemy = enemyPiece;
		Image p1i = GameImages.getImage( new Piece(me.color   , Direction.FRONT, Weapon.NONE, Revealed.NONE).getMap() );
		Image p2i = GameImages.getImage( new Piece(enemy.color, Direction.FRONT, Weapon.NONE, Revealed.NONE).getMap() );
		p1 = Utils.getScaledImage(Utils.toBufferedImage(p1i), IMAGE_SIZE);
	    p2 = Utils.getScaledImage(Utils.toBufferedImage(p2i), IMAGE_SIZE);
		 
		try {
			myWeaponImg = ImageIO.read(new File("res\\" + me.weapon.toString() + Settings.IMAGES_FILE_EXTENSION));
		} catch (IOException e) {
			e.printStackTrace();
		}
     
		try {
			enemyWeaponImg = ImageIO.read(new File("res\\" + enemy.weapon.toString() + Settings.IMAGES_FILE_EXTENSION));
		} catch (IOException e) {
			e.printStackTrace();
		}
		myWeaponImgOrg = myWeaponImg;
		enemyWeaponImgOrg = enemyWeaponImg;
	}
	
	public void startAnimation(Semaphore s) throws IOException {
	    timer = new Timer(MOVE_PIECE_ANIMATION_SPEED, new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				counter ++;
				repaint();
			}
		});
	    sem = s;
	    timer.start();
	}

	public void paintComponent (Graphics g) {
		super.paintComponent (g);
		Graphics2D g2 = (Graphics2D)g;
		
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
        roundRect.drawRect(g2);  
        
        double xForImages = (RECT_WIDTH - 2*IMAGE_SIZE - SPACING_SIDE) / 2;
        double yForImages = SPACING_UP;
       
        g2.drawImage(p1, (int) xForImages,(int) yForImages,null);
        g2.drawImage(p2, (int) (xForImages + IMAGE_SIZE + SPACING_SIDE),(int) yForImages,null);
        
        yForImages += p1.getHeight() + 2*SPACING_UP ;

		myWeaponImg = myWeaponImgOrg;
		enemyWeaponImg = enemyWeaponImgOrg;
	
        if (counter < (ANIMATION_MOVES /3)) { // Just show the weapons. If there's a tie, the animation stops after this
        	myWeaponImg = Utils.getScaledImage(Utils.toBufferedImage(myWeaponImg),IMAGE_SIZE);
        	enemyWeaponImg = Utils.getScaledImage(Utils.toBufferedImage(enemyWeaponImg), IMAGE_SIZE);
        	g2.drawImage( myWeaponImg, (int) xForImages, (int) yForImages, null);
        	g2.drawImage( enemyWeaponImg, (int) (xForImages + IMAGE_SIZE + SPACING_SIDE), (int) (yForImages ), null);
        	if  ((me.battle(enemy) == Piece.TIE) && (counter == ((ANIMATION_MOVES /3)-1)))  {
    			sem.release();
        		timer.stop();
    			return;
    		}
        }
        else if (counter < (ANIMATION_MOVES * 2/3)) { // The actual "battle". Enlarge the winner weapon and make the loser smaller
        	
        	int meTranform = me.battle(enemy);
        	int enemyTranform = -meTranform; // * (-1);
        	double offset = counter - (ANIMATION_MOVES/3);
        	
        	double meScale    = IMAGE_SIZE +    meTranform * offset * (IMAGE_SIZE/(ANIMATION_MOVES/3)); 
        	double enemyScale = IMAGE_SIZE + enemyTranform * offset * (IMAGE_SIZE/(ANIMATION_MOVES/3));
        	
        	double xForMeImage = xForImages + (IMAGE_SIZE - meScale)/2;  
        	double xForEnemyImage = xForImages + IMAGE_SIZE + SPACING_SIDE + (IMAGE_SIZE - enemyScale)/2  -(IMAGE_SIZE - meScale)/2;  
        	
        	myWeaponImg = Utils.getScaledImage(Utils.toBufferedImage(myWeaponImg),meScale);
        	enemyWeaponImg = Utils.getScaledImage(Utils.toBufferedImage(enemyWeaponImg), enemyScale);
        	
        	g2.drawImage(myWeaponImg, (int) xForMeImage, (int) yForImages, null);
        	g2.drawImage(enemyWeaponImg, (int) (xForEnemyImage), (int) (yForImages), null);
        	
        	closeMeScale = meScale;
        	closeEnemyScale = enemyScale;
        }
        else { // The last part of the animation. Simply freeze and show the big and small weapons a bit longer
        	        	
        	double xForMeImage = xForImages + (IMAGE_SIZE - closeMeScale)/2;  
        	double xForEnemyImage = xForImages + IMAGE_SIZE + SPACING_SIDE + (IMAGE_SIZE - closeEnemyScale)/2 - (IMAGE_SIZE - closeMeScale)/2;  
        	
        	myWeaponImg = Utils.getScaledImage(Utils.toBufferedImage(myWeaponImg), closeMeScale);
        	enemyWeaponImg = Utils.getScaledImage(Utils.toBufferedImage(enemyWeaponImg), closeEnemyScale);
        	
        	g2.drawImage( myWeaponImg ,(int) xForMeImage,(int) yForImages,null);
        	g2.drawImage( enemyWeaponImg ,(int) (xForEnemyImage),(int) (yForImages),null);
        	
            if (counter == ANIMATION_MOVES) {
            	timer.stop();
            	sem.release();
            }
        }
	}
}	
